home *** CD-ROM | disk | FTP | other *** search
/ BCI NET 2 / BCI NET 2.iso / archives / programming / source / tracker-4.13.lha / tracker / main.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-02-15  |  14.8 KB  |  551 lines

  1. /* main.c 
  2.     vi:ts=3 sw=3:
  3.  */
  4.  
  5. /* plays sound/noisetracker files on Sparc, silicon graphics.
  6.  * Authors  : Liam Corner - zenith@dcs.warwick.ac.uk
  7.  *            Marc Espie - espie@ens.fr
  8.  *            Steve Haehnichen - shaehnic@ucsd.edu
  9.  *            Andrew Leahy - alf@st.nepean.uws.edu.au
  10.  *
  11.  * Usage    : tracker <filename> 
  12.  *  this version plays compressed files as well.
  13.  */
  14.  
  15. /* $Id: main.c,v 4.13 1995/02/15 14:30:09 espie Exp espie $
  16.  * $Log: main.c,v $
  17.  * Revision 4.13  1995/02/15  14:30:09  espie
  18.  * optarg being NULL not checked -> segmentation.
  19.  *
  20.  * Revision 4.12  1995/02/14  16:50:29  espie
  21.  * *** empty log message ***
  22.  *
  23.  * Revision 4.12  1995/02/14  16:50:29  espie
  24.  * *** empty log message ***
  25.  *
  26.  * Revision 4.11  1995/02/14  04:02:28  espie
  27.  * Added version number.
  28.  *
  29.  * Revision 4.10  1995/02/08  13:14:56  espie
  30.  * *** empty log message ***
  31.  *
  32.  * Revision 4.9  1995/02/01  20:41:45  espie
  33.  * Added color.
  34.  *
  35.  * Revision 4.9  1995/02/01  20:41:45  espie
  36.  * Added color.
  37.  *
  38.  * Revision 4.8  1995/02/01  16:39:04  espie
  39.  * Loading formats thru rewind.
  40.  *
  41.  * Revision 4.8  1995/02/01  16:39:04  espie
  42.  * Loading formats thru rewind.
  43.  *
  44.  * Revision 4.5  1994/08/23  18:19:46  espie
  45.  * Added speed mode option.
  46.  * Added looping option.
  47.  * Nice OPT_CUT/OPT_ADD.
  48.  * Slight input/output changes.
  49.  * No more call to create_notes_table().
  50.  * Some notice to status.
  51.  * Use new pref scheme.
  52.  * Use info facility instead of printf for usage message.
  53.  * Options changes.
  54.  * Changed extended file semantics.
  55.  * Amiga support.
  56.  * Fixed upo previous song bug.
  57.  * Added bg/fg test.
  58.  * Added loads of new options.
  59.  * Added finetune.
  60.  *
  61.  * Revision 2.20  1992/11/17  17:06:25  espie
  62.  * Added PREVIOUS_SONG handling ???
  63.  * Use streamio for new interface (obsolescent signal handlers), and
  64.  * related changes.
  65.  * Cleaned up path reader, and better signal handling.
  66.  * Support for open_file.
  67.  * Added imask.
  68.  * Use transparent decompression/path lookup through open_file/close_file.
  69.  * Added setup_audio().
  70.  * Added some frequency/oversample/stereo change on the fly.
  71.  * Necessitates rightful closing/reopening of audio.
  72.  * Added compression methods. Changed getopt.
  73.  * Separated mix/stereo stuff.
  74.  * Added transpose feature.
  75.  * Added possibility to get back to MONO for the sgi.
  76.  * Added stereo capabilities to the indigo version.
  77.  * Added recovery and reread for automatic recognition
  78.  * of old/new tracker files.
  79.  * Added two level of fault tolerancy.
  80.  * Added more rational options.
  81.  * Moved almost everything to audio and automaton.
  82.  * Structured part of the code, especially replay ``automaton''
  83.  * and setting up of effects.
  84.  *
  85.  * Revision 1.26  1991/11/17  17:09:53  espie
  86.  * Added missing prototypes.
  87.  * Some more info while loading files.
  88.  * Added FAULT env variable, FAULT resistant playing,
  89.  * for playing modules which are not quite correct.
  90.  * Serious bug: dochangespeed was not reset all the time.
  91.  * Check all these parameters, they MUST be reset for
  92.  * each new song.
  93.  * Fixed a stupid bug: when env variable LOOPING was
  94.  * undefined, we got a segv on strcmp.
  95.  * Now we just test for its existence, since this is
  96.  * about all we want...
  97.  * Bug correction: when doing arpeggio, there might not
  98.  * be a new note, so we have to save the old note value
  99.  * and do the arppeggio on that note.
  100.  * Completely added control with OVERSAMPLE and FREQUENCY.
  101.  * Added control flow.
  102.  * Added pipe decompression, so that now you can do
  103.  * str32 file.Z directly.
  104.  * stdin may go away.
  105.  * Added arpeggio.
  106.  * Added vibslide and portaslide.
  107.  * Added speed command.
  108.  * Added signal control.
  109.  * Error checking: there shouldn't be that many
  110.  * segv signals any more.
  111.  * Moved every command to commands.c.
  112.  * Added some debug code for showing the full
  113.  * sequence for a file.
  114.  * Corrected the bug in volume slide: there is
  115.  * no default value, i.e., if it is 0, it is 0,
  116.  * as stupid as it may seem.
  117.  * Added vibrato.
  118.  * Added fastskip/corrected skip.
  119.  * Modified control flow of the player till
  120.  * it looks like something reasonable (i.e.,
  121.  * the structure is more natural and reflects
  122.  * the way stuff is played actually...)
  123.  * Do not restart the sound when we change instruments
  124.  * on the fly. A bit strange, but it works that way.
  125.  * Modified main to use new data structures.
  126.  * The sound player is MUCH cleaner, it uses now
  127.  * a 3-state automaton for each voice.
  128.  * Corrected ruckus with data type of sample.
  129.  */
  130.      
  131.  
  132. #include "defs.h"
  133. #include "version.h"
  134.  
  135. #include <signal.h>
  136. #include <ctype.h>
  137. #ifdef VOLUME_CONTROL
  138. #ifdef __hpux
  139. #define true /* kludge to avoid typedef of boolean (name clash with macro) */
  140. #include <audio/Alib.h>
  141. #undef true
  142. AGainDB    volume = -20;
  143. char use_speaker = 0;
  144. #endif
  145. #endif
  146.  
  147.      
  148. #include "song.h"
  149. #include "extern.h"
  150. #include "options.h"
  151.  
  152. #include "getopt.h"
  153. #include "tags.h"
  154. #include "prefs.h"
  155.      
  156. ID("$Id: main.c,v 4.13 1995/02/15 14:30:09 espie Exp espie $")
  157.  
  158.  
  159. LOCAL void print_usage()
  160.    {
  161.    GENERIC handle;
  162.    handle = begin_info("Usage");
  163.    infos(handle, "This is tracker ");
  164.     info(handle, VERSION);
  165.     info(handle, "This program is NOT to be redistributed");
  166.     info(handle, "         without the full documentation");
  167.     info(handle, "");
  168.    info(handle, "Usage: tracker [options] filename [...]");
  169.    info(handle, "-help               Display usage information");
  170.    info(handle, "-quiet              Print no output other than errors");
  171.    info(handle, "-picky              Do not tolerate any faults (default is to ignore most)");
  172.    info(handle, "-tolerant           Ignore all faults");
  173.    info(handle, "-mono               Select single audio channel output");
  174.    info(handle, "-stereo             Select dual audio channel output");
  175.    info(handle, "-verbose            Show text representation of song");
  176.    info(handle, "-repeats <count>    Number of repeats (0 is forever) (default 1)");
  177.     info(handle, "-loop               Loops the song list (plays again and again)");
  178.    info(handle, "-speed <speed>      Song speed.  Some songs want 60 (default 50)");
  179.    info(handle, "-mix <percent>      Percent of channel mixing. (0 = spatial, 100 = mono)");
  180.    info(handle, "-new -old -both     Select default reading type (default is -both)");
  181.    info(handle, "-frequency <freq>   Set playback frequency in Hz");
  182.    info(handle, "-oversample <times> Set oversampling factor");
  183.    info(handle, "-transpose <n>      Transpose all notes up");
  184.    info(handle, "-scroll             Show what's going on");
  185.    info(handle, "-color              Ansi color scrolling");
  186.    info(handle, "-sync               Try to synch audio output with display");
  187. #ifdef VOLUME_CONTROL
  188.     info(handle, "-speaker                 Output audio to internal speaker");
  189.     info(handle, "-volume <n>         Set volume in dB");
  190. #endif
  191.    info(handle, "");
  192.    info(handle, "RunTime:");
  193.    info(handle, "e,x     exit program");
  194.    info(handle, "n       next song");
  195.    info(handle, "p       restart/previous song");
  196.    info(handle, ">       fast forward");
  197.    info(handle, "<       rewind");
  198.    info(handle, "S       NTSC tempo\t s\tPAL tempo");
  199.    end_info(handle);
  200.    }
  201.  
  202. /* Command-line options. */
  203. LOCAL struct long_option long_options[] =
  204. {
  205.    {"help",                0, 'H', OPT_HELP},
  206.    {"quiet",               0, 'Q', OPT_QUIET}, 
  207.    {"picky",               0, 'P', OPT_PICKY},
  208.    {"tolerant",            0, 'L', OPT_TOLERANT},
  209.    {"new",                 0, 'N', OPT_NEWONLY},
  210.    {"old",                 0, 'O', OPT_OLDONLY},
  211.    {"both",                0, 'B', OPT_BOTH},
  212.    {"mono",                0, 'M', OPT_MONO},
  213.    {"stereo",              0, 'S', OPT_STEREO},
  214.    {"verbose",             0, 'V', OPT_VERBOSE},
  215.    {"frequency",           1, 'f', OPT_FREQUENCY},
  216.    {"oversample",          1, 'o', OPT_OVERSAMPLE},
  217.    {"transpose",           1, 't', OPT_TRANSPOSE},
  218.    {"repeats",             1, 'r', OPT_REPEATS},
  219.    {"speed",               1, 's', OPT_SPEED},
  220.    {"mix",                 1, 'm', OPT_MIX},
  221.    {"start",               1, 'X', OPT_START},
  222.    {"cut",                 1, '-', OPT_CUT},
  223.    {"add",                 1, '+', OPT_ADD},
  224.    {"scroll",              0, 'v', OPT_SHOW},
  225.     {"color",                    0, 'c', OPT_COLOR},    
  226.    {"sync",                0, '=', OPT_SYNC},
  227.     {"loop",                        0, 'l', OPT_LOOP},
  228.     {"speedmode",               1, '?', OPT_SPEEDMODE},
  229. #ifdef VOLUME_CONTROL
  230.     {"speaker",                    0, '#', OPT_SPEAKER},
  231.     {"volume",                    1, 'u', OPT_VOLUME},
  232. #endif
  233.    {0,                     0,  0 , 0}
  234. };
  235.  
  236.  
  237. /* global variable to catch various types of errors
  238.  * and achieve the desired flow of control
  239.  */
  240. int error;
  241.  
  242. LOCAL int optvalue(def)
  243. int def;
  244.    {
  245.    int d;
  246.  
  247.    if (optarg && sscanf(optarg, "%d", &d) == 1)
  248.       return d;
  249.    else
  250.       {
  251.       optind--;
  252.       return def;
  253.       }
  254.    }
  255.  
  256. LOCAL int ask_freq;
  257. LOCAL int oversample;
  258. LOCAL int stereo;
  259. LOCAL int start;
  260. LOCAL int transpose;
  261. LOCAL int loop = FALSE;
  262.  
  263.  
  264. LOCAL void parse_options(argc, argv)
  265. int argc;
  266. char *argv[];
  267.    {
  268.    int c;
  269.    
  270.    while ((c = getlongopt(argc, argv, long_options))
  271.       != BAD_OPTION)
  272.       switch(c)
  273.          {
  274.         case OPT_LOOP:
  275.             loop = TRUE;
  276.             break;
  277.         case OPT_CUT:
  278.         case OPT_ADD:
  279.             {
  280.             int i;
  281.             unsigned long imask = 0;
  282.       
  283.             for (i = 0; optarg && optarg[i]; i++)
  284.                 {
  285.                 char c = tolower(optarg[i]);
  286.  
  287.                 if (c >= '1' && c <= '9')
  288.                     imask |= 1<< (c-'1');
  289.                 else if (c >= 'a' && c <= 'z')
  290.                     imask |= 1 << (c-'a'+9);
  291.                 }
  292.             if (c == OPT_ADD)
  293.                 set_pref_scalar(PREF_IMASK, ~imask);
  294.             else
  295.                 set_pref_scalar(PREF_IMASK, imask);
  296.             }        
  297.          break;
  298.         case OPT_SPEEDMODE:
  299.             if (optarg)
  300.                 {
  301.                 if (stricmp(optarg, "old") == 0)
  302.                     set_pref_scalar(PREF_SPEEDMODE, OLD_SPEEDMODE);
  303.                 else if (stricmp(optarg, "normal") == 0)
  304.                     set_pref_scalar(PREF_SPEEDMODE, NORMAL_SPEEDMODE);
  305.                 else if (stricmp(optarg, "finefirst") == 0)
  306.                     set_pref_scalar(PREF_SPEEDMODE, FINESPEED_ONLY);
  307.                 else if (stricmp(optarg, "normalfirst") == 0)
  308.                     set_pref_scalar(PREF_SPEEDMODE, SPEED_ONLY);
  309.                 }
  310.             break;
  311.             
  312.       case OPT_OLDONLY:   /* old tracker type */
  313.          set_pref_scalar(PREF_TYPE, OLD);
  314.          break;
  315.       case OPT_NEWONLY:   /* new tracker type */
  316.          set_pref_scalar(PREF_TYPE, NEW);
  317.          break;
  318.       case OPT_SHOW:
  319.          set_pref_scalar(PREF_SHOW, TRUE);
  320.          break;
  321.         case OPT_COLOR:
  322.             set_pref_scalar(PREF_COLOR, TRUE);
  323.             break;
  324.       case OPT_SYNC:
  325.          set_pref_scalar(PREF_SYNC, TRUE);
  326.          break;
  327.       case OPT_BOTH:   /* both tracker types */
  328.          set_pref_scalar(PREF_TYPE, BOTH);
  329.          break;
  330.       case OPT_REPEATS:   /* number of repeats */
  331.          set_pref_scalar(PREF_REPEATS, optvalue(0));
  332.          break;
  333.       case OPT_SPEED:  
  334.          set_pref_scalar(PREF_SPEED, optvalue(50));
  335.          break;
  336.       case OPT_MONO:  
  337.          stereo = FALSE;
  338.          break;
  339.       case OPT_STEREO:  
  340.          stereo = TRUE;
  341.          break;
  342.       case OPT_OVERSAMPLE:  
  343.          oversample = optvalue(1);
  344.          break;
  345.       case OPT_FREQUENCY:
  346.          ask_freq = optvalue(0) * 1000;
  347.          break;
  348.       case OPT_TRANSPOSE:
  349.          transpose = optvalue(0);
  350.          break;
  351.       case OPT_PICKY:
  352.          set_pref_scalar(PREF_TOLERATE, 0);
  353.          break;
  354.       case OPT_TOLERANT:
  355.          set_pref_scalar(PREF_TOLERATE, 2);
  356.          break;
  357.       case OPT_MIX:     /* % of channel mix. 
  358.                          * 0->full stereo, 100->mono */
  359.          set_mix(optvalue(30));
  360.          break;
  361.       case OPT_START:
  362.          start = optvalue(0);
  363.          break;
  364.       case OPT_HELP:
  365.          print_usage();
  366.          end_all(0);
  367.          /* NOTREACHED */
  368.       case OPT_VERBOSE:
  369.          set_pref_scalar(PREF_DUMP, TRUE);
  370.             break;
  371. #ifdef VOLUME_CONTROL
  372.         case OPT_VOLUME:
  373.             volume = optvalue(-20);
  374.             break;
  375.         case OPT_SPEAKER:
  376.             use_speaker = 1;
  377.             break;
  378. #endif
  379.          }
  380.    }
  381.  
  382. LOCAL struct song *load_song(name)
  383. char *name;
  384.    {
  385.    struct song *song;
  386.    char *buffer;
  387.     struct exfile *file;
  388.    int i, j;
  389.    
  390.    i = strlen(name);
  391.    
  392.    for (j = i; j > 0; j--)
  393.       if (name[j] == '/' || name[j] == '\\')
  394.          {
  395.          j++;
  396.          break;
  397.          }
  398.    
  399.    buffer = malloc( i - j + 5);
  400.    if (buffer)
  401.       {
  402.       sprintf(buffer, "%s...", name + j);
  403.       status(buffer);
  404.       }
  405.  
  406.     file = open_file(name, "r", getenv("MODPATH"));
  407.     if (file)
  408.         {
  409.         switch(get_pref_scalar(PREF_TYPE))
  410.             {
  411.         case BOTH:
  412.             song = read_song(file, NEW);
  413.             if (song)
  414.                 break;
  415.             else
  416.                 rewind_file(file);
  417.             /* FALLTHRU */
  418.         case OLD:
  419.             song = read_song(file, OLD);
  420.             break;
  421.             /* this is explicitly flagged as a new module,
  422.              * so we don't need to look for a signature.
  423.              */
  424.         case NEW:
  425.             song = read_song(file, NEW_NO_CHECK);
  426.             break;
  427.         default:
  428.             song = NULL;
  429.             }
  430.         close_file(file);
  431.         }
  432.     if (buffer)
  433.         {
  434.         status(0);
  435.         free(buffer);
  436.         }
  437.     return song;
  438.    }
  439.  
  440. int main(argc, argv)
  441. int argc;
  442. char **argv;
  443.    {
  444.    struct song *song;
  445.    int *is_song;
  446.    int i;
  447.  
  448.    struct tag *result;
  449.  
  450.     EXPAND_WILDCARDS(argc,argv);
  451.  
  452.    is_song = (int *)malloc(sizeof(int) * argc);
  453.    if (!is_song)
  454.       end_all("No memory left");
  455.  
  456.    for (i = 0; i < argc; i++)
  457.       is_song[i] = FALSE;        /* For termination */
  458.  
  459.    start = 0;
  460.    set_pref_scalar(PREF_IMASK, 0);
  461.    set_pref_scalar(PREF_BCDVOL, 0);
  462.    set_pref_scalar(PREF_DUMP, FALSE);
  463.    set_pref_scalar(PREF_SHOW, FALSE);
  464.    set_pref_scalar(PREF_COLOR, FALSE);
  465.    set_pref_scalar(PREF_SYNC, FALSE);
  466.    set_pref_scalar(PREF_TYPE, BOTH);
  467.    set_pref_scalar(PREF_REPEATS, 1);
  468.    set_pref_scalar(PREF_SPEED, 50);
  469.    set_pref_scalar(PREF_TOLERATE, 1);
  470.     set_pref_scalar(PREF_SPEEDMODE, NORMAL_SPEEDMODE);
  471.  
  472.    if (argc == 1)
  473.       {
  474.       print_usage();
  475.       end_all(0);
  476.       }
  477.  
  478.    ask_freq = read_env("FREQUENCY", 0);
  479.    oversample = read_env("OVERSAMPLE", 1);
  480.    transpose = read_env("TRANSPOSE", 0);
  481.    stereo = !getenv("MONO");
  482.    set_mix(30);
  483.  
  484.  
  485.  
  486.       /* check the command name for default reading type */
  487.  
  488.  
  489. looping:
  490.    for (optind = 1; optind < argc; optind++)
  491.       {
  492.       parse_options(argc, argv);
  493.       if (optind >= argc)
  494.          end_all(0);
  495.          
  496.    
  497.       song = load_song(argv[optind]);   
  498.       if (song)
  499.          is_song[optind] = TRUE;
  500.       else
  501.          {
  502.          puts("not a song");
  503.          is_song[optind] = FALSE;
  504.          continue;
  505.          }
  506. play_on:
  507.       if (get_pref_scalar(PREF_DUMP))
  508.          dump_song(song); 
  509.       transpose_song(song, transpose);
  510.       setup_audio(ask_freq, stereo, oversample);
  511.       result = play_song(song, start);
  512.       release_song(song);
  513.       status(0);
  514.       while (result = get_tag(result))
  515.          {
  516.          switch (result->type)
  517.             {
  518.          case PLAY_PREVIOUS_SONG:
  519.             optind--;
  520.             while ((optind > 0) && !is_song[optind])
  521.                optind--;
  522.             if (optind == 0)
  523.                     {
  524.                     if (loop)
  525.                         optind = argc - 1;
  526.                     else
  527.                         end_all(0);
  528.                     }
  529.                 song = load_song(argv[optind]);
  530.                 goto play_on;
  531.             /* NOTREACHED */
  532.          case PLAY_LOAD_SONG:
  533.             song = load_song(result->data.pointer);
  534.             free(result->data.pointer);
  535.             if (song)
  536.                goto play_on;
  537.          default:
  538.             break;
  539.             }
  540.          result++;
  541.          }
  542.             
  543.       }
  544.     if (loop)
  545.         goto looping;
  546.    end_all(0);
  547.    /* NOTREACHED */
  548.    }
  549.  
  550.  
  551.